// AFNetworkActivityConsoleLogger.h
//
// Copyright (c) 2018 AFNetworking (http://afnetworking.com/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#import "AFNetworkActivityConsoleLogger.h"
#import <AFNetworking/AFURLResponseSerialization.h>

@interface AFNetworkActivityConsoleLogger ()

@property (nonatomic, strong) AFJSONResponseSerializer *afJSONResponseSerializer;

@end

@implementation AFNetworkActivityConsoleLogger

- (id)init {
    self = [super init];
    if (!self) {
        return nil;
    }

    self.level = AFLoggerLevelInfo;

    return self;
}


- (void)URLSessionTaskDidStart:(NSURLSessionTask *)task {
    NSURLRequest *request = task.originalRequest;

    NSString *body = nil;
    if ([request HTTPBody]) {
        body = [[NSString alloc] initWithData:[request HTTPBody] encoding:NSUTF8StringEncoding];
    }

    switch (self.level) {
        case AFLoggerLevelDebug: {
            NSMutableString *text = [[NSMutableString alloc] init];
            [text appendString:@"[Request] ->\n"];
            [text appendString:[NSString stringWithFormat:@"Uri: %@\n", [[request URL] absoluteString]]];
            [text appendString:[NSString stringWithFormat:@"Method: %@\n", [request HTTPMethod]]];
            [text appendString:@"Headers:\n"];
            NSMutableString *responseHeaderText = [self responseHeaderText:[request allHTTPHeaderFields]];
            [text appendString:[NSString stringWithFormat:@"%@\n", responseHeaderText]];
            [text appendString:@"Request Body:\n"];
            [text appendString:[NSString stringWithFormat:@"%@\n", body]];
            NSLog(@"%@", text);
//            NSLog(@"%@ '%@': %@ %@", [request HTTPMethod], [[request URL] absoluteString], [request allHTTPHeaderFields], body);
            break;
        }
        case AFLoggerLevelInfo:
            NSLog(@"%@ '%@'", [request HTTPMethod], [[request URL] absoluteString]);
            break;
        default:
            break;
    }
}

- (void)URLSessionTaskDidFinish:(NSURLSessionTask *)task withResponseObject:(id)responseObject inElapsedTime:(NSTimeInterval )elapsedTime withError:(NSError *)error {
    NSUInteger responseStatusCode = 0;
    NSDictionary *responseHeaderFields = nil;
    if ([task.response isKindOfClass:[NSHTTPURLResponse class]]) {
        responseStatusCode = (NSUInteger)[(NSHTTPURLResponse *)task.response statusCode];
        responseHeaderFields = [(NSHTTPURLResponse *)task.response allHeaderFields];
    }

    if (error) {
        switch (self.level) {
            case AFLoggerLevelDebug:
            case AFLoggerLevelInfo:
            case AFLoggerLevelError: {
//                NSLog(@"[Error] %@ '%@' (%ld) [%.04f s]: %@", [task.originalRequest HTTPMethod], [[task.response URL] absoluteString], (long)responseStatusCode, elapsedTime, error);
                
                NSMutableString *text = [[NSMutableString alloc] init];
                [text appendString:@"[Response]  << Error >>  ->\n"];
                [text appendString:[NSString stringWithFormat:@"Uri: %@\n", [[task.response URL] absoluteString]]];
                [text appendString:[NSString stringWithFormat:@"Request Method: %@\n", [task.originalRequest HTTPMethod]]];
                [text appendString:[NSString stringWithFormat:@"Status Code: %ld\n", (long)responseStatusCode]];
                [text appendString:[NSString stringWithFormat:@"Time: [%.04f s]\n", elapsedTime]];
                [text appendString:@"Error Info:\n"];
                [text appendString:[NSString stringWithFormat:@"%@\n", error]];
                NSLog(@"%@", text);
            }
            default:
                break;
        }
    } else {
        switch (self.level) {
            case AFLoggerLevelDebug: {
//                if (request.responseSerializerType != PPNetResponseSerializer_raw)
                
                id jsonObject = responseObject;
                NSError *serializationError = nil;
                if (![responseObject isKindOfClass:NSDictionary.class]) {
                    AFHTTPResponseSerializer *responseSerializer = [self afJSONResponseSerializer];
                    if ([responseObject isKindOfClass:NSData.class]) {
                        jsonObject = [responseSerializer responseObjectForResponse:task.response data:responseObject error:&serializationError];
                    }
                }
                NSString *json = [self dictionaryToJSONString:jsonObject];
                NSMutableString *responseHeaderText = [self responseHeaderText:responseHeaderFields];
//                NSLog(@"%ld '%@' [%.04f s]: %@ %@", (long)responseStatusCode, [[task.response URL] absoluteString], elapsedTime, responseHeaderText, json);
                
                NSMutableString *text = [[NSMutableString alloc] init];
                [text appendString:@"[Response] ->\n"];
                [text appendString:[NSString stringWithFormat:@"Uri: %@\n", [[task.response URL] absoluteString]]];
                [text appendString:[NSString stringWithFormat:@"Request Method: %@\n", [task.originalRequest HTTPMethod]]];
                [text appendString:[NSString stringWithFormat:@"Status Code: %ld\n", (long)responseStatusCode]];
                [text appendString:[NSString stringWithFormat:@"Time: [%.04f s]\n", elapsedTime]];
                [text appendString:@"Response Body:\n"];
                [text appendString:[NSString stringWithFormat:@"%@\n", json]];
                NSLog(@"%@", text);
            }
                break;
            case AFLoggerLevelInfo:
                NSLog(@"%ld '%@' [%.04f s]", (long)responseStatusCode, [[task.response URL] absoluteString], elapsedTime);
                break;
            default:
                break;
        }
    }
}

- (NSMutableString *)responseHeaderText:(NSDictionary *)headerFields {
    NSMutableString *text = [[NSMutableString alloc] init];
    [headerFields enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        [text appendString:[NSString stringWithFormat:@"  %@: %@\n ", key, obj]];
    }];
    return text;
}

- (NSString *)dictionaryToJSONString:(NSDictionary *)dictionary {
    if (!dictionary) {
        return nil;
    }
    if ([dictionary isKindOfClass:NSURL.class]) {
        return [NSString stringWithFormat:@"%@", dictionary];
    }
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
//    NSString *jsonTemp = [jsonString stringByReplacingOccurrencesOfString:@"\n" withString:@""];
//    NSString *jsonResult = [jsonTemp stringByReplacingOccurrencesOfString:@" " withString:@""];
    return jsonString;
}

- (AFJSONResponseSerializer *)afJSONResponseSerializer {
    if (!_afJSONResponseSerializer) {
        _afJSONResponseSerializer = [AFJSONResponseSerializer serializer];
        _afJSONResponseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html", @"application/json", @"text/json",  @"text/javascript", @"text/plain", nil];
    }
    return _afJSONResponseSerializer;
}

@end
